//#define __NO_STD_VECTOR // Use cl::vector instead of STL version
//#define __CL_ENABLE_EXCEPTIONS
//#include <CL/cl.hpp>
//#include <utility>
//#include <iostream>
//#include <fstream>
//#include <string>
//#include <vector>
//#include <sstream>
//#include <time.h>
//
//class InputMatrix {
//	int rows;
//	int cols;
//	std::vector<std::vector<float>> matrix;
//
//public:
//	InputMatrix(int, int, std::vector<std::vector<float>>);
//	void setPosition(int, int);
//	int getRows();
//	int getCols();
//	std::vector<std::vector<float>> getMatrix();
//
//};
//
//InputMatrix::InputMatrix(int a, int b, std::vector<std::vector<float>> inMatrix) {
//	rows = a;
//	cols = b;
//	matrix = inMatrix;
//}
//
//int InputMatrix::getRows() {
//	return rows;
//}
//
//int InputMatrix::getCols() {
//	return cols;
//}
//
//std::vector<std::vector<float>> InputMatrix::getMatrix() {
//	return matrix;
//}
//
//class EllPackedMatrix {
//	float * values;
//	int * colIdx;
//	int maxNonZero;
//	int rows;
//
//public:
//	EllPackedMatrix(float * values, int * colIdx, int maxNonZero, int rows);
//	float * getValues();
//	int * getColIdx();
//	int getMaxNonZero();
//	int getRows();
//};
//
//EllPackedMatrix::EllPackedMatrix(float * values, int * colIdx, int maxNonZero, int rows) {
//	this->values = values;
//	this->colIdx = colIdx;
//	this->maxNonZero = maxNonZero;
//	this->rows = rows;
//}
//
//float * EllPackedMatrix::getValues() {
//	return values;
//}
//
//int * EllPackedMatrix::getColIdx() {
//	return colIdx;
//}
//
//int EllPackedMatrix::getMaxNonZero() {
//	return maxNonZero;
//}
//
//int EllPackedMatrix::getRows() {
//	return rows;
//}
//
//using namespace cl;
//clock_t init, final;
//
//EllPackedMatrix ellPack(InputMatrix input) {
//	int maxNonZero = 0;
//	float * values;
//	int * colIdx;
//
//	int rows = input.getRows();
//	int cols = input.getCols();
//
//	for(int row = 0; row < rows; row++) {
//		int rowNoneZero = 0;
//		for(int col = 0; col < cols; col++) {	
//			if(input.getMatrix()[row][col]>0.0) {
//				rowNoneZero++;
//			}
//		}
//		if(maxNonZero < rowNoneZero) {
//			maxNonZero = rowNoneZero;
//		}
//	}
//
//	int g = maxNonZero*rows;
//	values = new float[g];
//	colIdx = new int[g];
//
//	int idx = 0;
//	int inCurRow = 0;
//	
//	values[idx] = 0.0;
//	for(int row = 0; row < rows; row++) {
//		for(int col = 0; col < cols; col++) {	
//			if(input.getMatrix()[row][col]>0.0) {			
//				values[idx] = input.getMatrix()[row][col];
//				colIdx[idx] = col;
//				idx++;
//				inCurRow++;
//			}
//		}
//		while(inCurRow < maxNonZero) {
//			values[idx] = 0.0;
//			colIdx[idx] = 0;
//			idx++;
//			inCurRow++;
//		}
//		inCurRow = 0;
//	}
//	EllPackedMatrix ellPackedMatrix(values, colIdx, maxNonZero, rows);
//
//	std::cout << "Values / Col_idx " << std::endl;
//	for(int i = 0; i < g; i++) {
//		std::cout << values[i] << "    /    " << colIdx[i] << std::endl;
//	}
//	std::cout << "Max non-zero: " << maxNonZero << std::endl;
//
//	return ellPackedMatrix;
//}
//
//int main() {
//	const int MATRIX_ROWS = 1000;
//	const int MATRIX_COLS = 1000;
//	std::ifstream ifs("matrix.txt");
//	
//	std::vector<std::vector<float>> matrix;
//
//	for(int i = 0; i < MATRIX_ROWS; i++)
//		matrix.push_back(std::vector<float>(MATRIX_COLS));
//
//	float readFloat;
//
//	int curRow = 0;
//	int curCol = 0;
//
//	while(ifs >> readFloat) {
//		if(curCol >= MATRIX_COLS-1) {
//			matrix[curRow][curCol] = readFloat;
//			curCol = 0;			
//			curRow++;
//		} else {
//			matrix[curRow][curCol] = readFloat;
//			curCol++;
//		}	
//	}	
//
//	ifs.close();
//
//	std::ifstream ifs2("vector.txt");
//	float * vectorInput = new float[MATRIX_ROWS];
//	int curPos = 0;
//
//	while(ifs2 >> readFloat) {				
//		vectorInput[curPos] = readFloat;
//		curPos++;
//	}	
//	ifs2.close();
//
//	std::cout << "Size of matrix:" << matrix.size() << std::endl;
//	//std::cout << "Size of vector:" << vectorInput.size() << std::endl;
//
//	//InputMatrix tMatrix(4,4,testMatrix);
//	InputMatrix inMatrix(MATRIX_ROWS, MATRIX_COLS, matrix);
//	//EllPackedMatrix ellPackedMatrix = ellPack(tMatrix);
//	EllPackedMatrix ellPackedMatrix2 = ellPack(inMatrix);
//
//	float * answer = new float[MATRIX_ROWS];
//	init=clock();
//   try { 
//        // Get available platforms
//        vector<Platform> platforms;
//        Platform::get(&platforms);
// 
//        // Select the default platform and create a context using this platform and the GPU
//        cl_context_properties cps[3] = { 
//            CL_CONTEXT_PLATFORM, 
//            (cl_context_properties)(platforms[0])(), 
//            0 
//        };
//        Context context( CL_DEVICE_TYPE_CPU, cps);
// 
//        // Get a list of devices on this platform
//        vector<Device> devices = context.getInfo<CL_CONTEXT_DEVICES>();
// 
//        // Create a command queue and use the first device
//        CommandQueue queue = CommandQueue(context, devices[0]);
// 
//        // Read source file
//        std::ifstream sourceFile("ellpack.cl");
//        std::string sourceCode(
//            std::istreambuf_iterator<char>(sourceFile),
//            (std::istreambuf_iterator<char>()));
//        Program::Sources source(1, std::make_pair(sourceCode.c_str(), sourceCode.length()+1));
// 
//        // Make program of the source code in the context
//        Program program = Program(context, source);
// 
//        // Build program for these specific devices
//        program.build(devices);
// 
//        //// Make kernel
//        Kernel kernel(program, "mvm_0");
//
//	//	//----------------------------------------------------
//
//		
//		int rows = ellPackedMatrix2.getRows();
//		int nonZeros = ellPackedMatrix2.getMaxNonZero();
//		float * values = ellPackedMatrix2.getValues();
//		int * colIdx = ellPackedMatrix2.getColIdx();
//		int maxNonZero = ellPackedMatrix2.getMaxNonZero();
//
//		Buffer bufferValues = Buffer(context, CL_MEM_READ_ONLY, (maxNonZero * rows) * sizeof(float));
//		Buffer bufferColIdx = Buffer(context, CL_MEM_READ_ONLY, (maxNonZero * rows) * sizeof(int));
//		Buffer bufferRows = Buffer(context, CL_MEM_READ_ONLY, sizeof(int));
//		Buffer bufferNonZeros = Buffer(context, CL_MEM_READ_ONLY, sizeof(int));
//		Buffer bufferVector = Buffer(context, CL_MEM_READ_ONLY, rows*sizeof(float));
//		Buffer bufferAnswer = Buffer(context, CL_MEM_WRITE_ONLY, rows*sizeof(float));
//
//		queue.enqueueWriteBuffer(bufferValues, CL_TRUE, 0, (maxNonZero * rows) * sizeof(float), values);		
//        //queue.enqueueWriteBuffer(bufferRows, CL_TRUE, 0, sizeof(int), (void *) &rows);		
//		//queue.enqueueWriteBuffer(bufferNonZeros, CL_TRUE, 0, sizeof(int), &maxNoneZero);
//		queue.enqueueWriteBuffer(bufferVector, CL_TRUE, 0, rows*sizeof(float), vectorInput);
//		queue.enqueueWriteBuffer(bufferColIdx, CL_TRUE, 0, (maxNonZero * rows) * sizeof(int), colIdx);
//
//		kernel.setArg(0, bufferValues);
//		kernel.setArg(1, rows);
//		kernel.setArg(2, maxNonZero);
//		kernel.setArg(3, bufferVector);
//		kernel.setArg(4, bufferAnswer);
//		kernel.setArg(5, bufferColIdx);
//
//		NDRange global(rows);
//        NDRange local(1);
//        queue.enqueueNDRangeKernel(kernel, NullRange, global, local);
//		queue.enqueueReadBuffer(bufferAnswer, CL_TRUE, 0, rows * sizeof(float), answer);
//	//	//----------------------------------------------------
// 
//    } catch(Error error) {
//       std::cout << error.what() << "(" << error.err() << ")" << std::endl;
//    }
//		final=clock()-init;
//		std::cout << "time: " << (double)final / ((double)CLOCKS_PER_SEC) << std::endl;
//		std::cout << "a[0]: " << answer[0] << std::endl;
//		std::cout << "a[1]: " << answer[1] << std::endl;
//		std::cout << "a[2]: " << answer[2] << std::endl;
//		std::cout << "a[3]: " << answer[3] << std::endl;
//		std::cout << "a[4]: " << answer[4] << std::endl;
//	char myChar;
//	std::cin >> myChar;
//	return 0;
//
//}